package predictor;

import imdb_db.Imdb;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;

import omdb.Omdb;

import org.jsoup.Jsoup;
import org.jsoup.nodes.*;
import org.jsoup.select.*;

import types.Movie;

/**
 * this class combines imdb, omdb and boxoffice information , generate feature vector and save then into a file.
 * @author chenji
 *
 */
public class Predictor {
	List<Movie> movieList;
	HashMap<String, Movie> movieMap = new HashMap<String, Movie>();
	TreeSet<String> studios = new TreeSet<String>();
	public Predictor(List<Movie> list) {
		this.movieList = list;
	}

	private String getOmdbInfo(Movie movie) throws Exception {
		String title = movie.getTitle();
		if (title.startsWith("#"))
			return title + " -e error";
		int year = movie.getYear();
		String dir = movie.getDir();
		String release = movie.getRelease();
		// /System.out.print(title + "," + dir + "," + year + "," + release);
		String info = "";
		info = Omdb.getMovieInfo("t=" + URLEncoder.encode(title, "UTF-8"));
		// System.out.println(info);
		String _release = "";
		String _dir = "";
		String _year = "";
		int y1, y2;
		if (info.contains("Released\"")) {
			_release = info.substring(info.indexOf("Released\""));
			_release = _release.substring(_release.indexOf("\"") + 3);
			_release = _release.substring(0, _release.indexOf("\""));
			if (release.equals(_release)) {
				// /System.out.println(" -r " + _release);
				return info;
			}
		}
		if (info.contains("Year\"")) {
			_year = info.substring(info.indexOf("Year\""));
			_year = _year.substring(_year.indexOf("\"") + 3);
			_year = _year.substring(0, _year.indexOf("\""));
			_year = _year.substring(0, 4);
		}
		// System.out.println(info);
		y1 = _year.length() == 0 ? -1 : Integer.parseInt(_year);
		y2 = (_release.length() == 0 || _release.endsWith("N/A")) ? -1 : Integer.parseInt(_release.split(" ")[2]);
		if ((Math.abs(y1 - year) <= 1 || Math.abs(y2 - year) <= 1) && info.contains("Director\"")) {
			_dir = info.substring(info.indexOf("Director\""));
			_dir = _dir.substring(_dir.indexOf("\"") + 3);
			_dir = _dir.substring(0, _dir.indexOf("\""));
			String[] _dirs = _dir.split(",");
			for (String d : _dirs) {
				d = d.trim();
				// System.out.println("dir: " + d);
				String[] d_split = d.split(" ");
				if (dir.contains(d_split[0]) && dir.contains(d_split[d_split.length - 1])) {
					// /System.out.println(" -d " + _year + "," + _release + "," + _dir);
					return info;
				}
			}
		}
		int[] ys = { 0, -1, 1 };
		for (int y : ys) {
			info = Omdb.getMovieInfo("t=" + URLEncoder.encode(title, "UTF-8") + "&y=" + (year + y));
			// System.out.println(info);
			if (info.contains("Released\"")) {
				_release = info.substring(info.indexOf("Released\""));
				_release = _release.substring(_release.indexOf("\"") + 3);
				_release = _release.substring(0, _release.indexOf("\""));
				if (release.equals(_release)) {
					// /System.out.println(" -r " + (year + y) + " -- " + _release);
					return info;
				}
			}
			if (info.contains("Year\"")) {
				_year = info.substring(info.indexOf("Year\""));
				_year = _year.substring(_year.indexOf("\"") + 3);
				_year = _year.substring(0, _year.indexOf("\""));
			}
			y1 = _year.length() == 0 ? -1 : Integer.parseInt(_year);
			y2 = (_release.length() == 0 || _release.endsWith("N/A")) ? -1 : Integer.parseInt(_release.split(" ")[2]);
			if ((Math.abs(y1 - year) <= 1 || Math.abs(y2 - year) <= 1) && info.contains("Director\"")) {
				_dir = info.substring(info.indexOf("Director\""));
				_dir = _dir.substring(_dir.indexOf("\"") + 3);
				_dir = _dir.substring(0, _dir.indexOf("\""));
				String[] _dirs = _dir.split(",");
				for (String d : _dirs) {
					d = d.trim();
					// System.out.println("dir: " + d);
					String[] d_split = d.split(" ");
					if (dir.contains(d_split[0]) && dir.contains(d_split[d_split.length - 1])) {
						// /System.out.println(" -d " + (year + y) + " -- " + _year + "," +
						// _release + "," + _dir);
						return info;
					}
				}
			}
		}
		for (Movie m : Imdb.sendGet(URLEncoder.encode(title, "ISO-8859-1"))) {
			// System.out.println("dir: " + m.getDir());
			String[] d_split = m.getDir().split(" ");
			if (dir.contains(d_split[0]) && dir.contains(d_split[d_split.length - 1]) && Math.abs(year - m.getYear()) <= 1) {
				// /System.out.println(" -i " + m.getId() + "," + m.getDir());
				return Omdb.getMovieInfo("i=" + m.getId());
			}
		}
		// /System.out.println(" -e error");
		return title + "," + dir + "," + year + "," + release + " -e error";
	}

	private String getMojoTable(Movie movie, String link, String start) throws Exception {
		// System.out.println(link);
		URL obj = new URL(link);
		HttpURLConnection con = (HttpURLConnection) obj.openConnection();
		con.setRequestMethod("GET");
		con.setRequestProperty("User-Agent", "Mozilla/5.0");

		BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
		String line;
		String table = "";
		boolean found = false;
		while ((line = reader.readLine()) != null) {
			// System.out.println(line);
			if (line.indexOf(start) != -1) {
				found = true;
				if (line.contains("<table"))
					table = line.substring(line.indexOf("<table"));
				while ((line = reader.readLine()) != null) {
					if (line.indexOf("</table>") != -1) {
						table += line.substring(0, line.indexOf("</table>") + 8);
						break;
					}
					table += line;
				}
			}
		}
		if (!found) {
			System.out.println("Movie Not found: " + movie.getAka() + " -- " + "http://www.boxofficemojo.com/search/?q="
					+ (URLEncoder.encode(movie.getAka(), "ISO-8859-1")));
		}
		reader.close();
		con.disconnect();
		return table;
	}

	public void addOmdbInfo() throws Exception {
		File file = new File("movie-check2");
		FileOutputStream out = new FileOutputStream(file);
		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
		String info = "";
		for (Movie movie : movieList) {
			info = getOmdbInfo(movie);
			if (info.endsWith("-e error")) {
				System.out.println(info);
			}
			if (info.contains("\"Response\":\"False\"")) {
				System.out.println(info);
			}
			if (!info.endsWith("-e error")) {
				movie.omdbInfo(info).setDate();

				String table = getMojoTable(
						movie,
						"http://www.boxofficemojo.com/search/?q="
								+ URLEncoder.encode(movie.getAka().replaceAll(",", ""), "ISO-8859-1"), "Movie Matches:");
				// System.out.println(table);
				String theater;
				boolean found = false;
				String date = movie.getDate();
				// System.out.println(date);
				Element movie_match = Jsoup.parse(table);
				Iterator<Element> it = movie_match.select("tr").iterator();
				it.next();
				while (it.hasNext()) {
					Element tr = it.next();
					Element td = tr.select("td").get(6);
					// System.out.println(td.text());
					if (td.text().contains("multiple")) {
						String link = "http://www.boxofficemojo.com" + td.select("a").first().attr("href");
						// System.out.println(movie.getAka() + " " + link);
						String multiple = getMojoTable(movie, link, "Lifetime Gross:");
						Element movie_multiple = Jsoup.parse(multiple);
						Iterator<Element> it2 = movie_multiple.select("tr").iterator();
						it2.next();
						while (it2.hasNext()) {
							Element tr2 = it2.next();
							Element td2 = tr2.select("td").get(0);
							int day = Integer.parseInt(td2.text().split("/")[1]);
							int month = Integer.parseInt(td2.text().split("/")[0]);
							int year = Integer.parseInt(td2.text().split("/")[2]);
							if (movie.getDay() == day && movie.getMonth() == month && movie.getYear() == year) {
								found = true;
							}
						}
					} else if (td.text().contains(date)){
						int day = Integer.parseInt(td.text().split("/")[1]);
						int month = Integer.parseInt(td.text().split("/")[0]);
						int year = Integer.parseInt(td.text().split("/")[2]);
						if (movie.getDay() == day && movie.getMonth() == month && movie.getYear() == year) {
							found = true;
						}
					}
					if (found) {
						//System.out.println(tr.select("td").get(3).text() +  " -- " + movie.getAka());
						if (tr.select("td").get(3).text().equalsIgnoreCase("n/a")) {
							System.out.println(tr.select("td").get(3).text() +  " -- " + movie.getAka());
						}
						movie.theater(tr.select("td").get(3).text());
						break;
					}
				}
				if (!found) {
					System.out.println("Release Not Found: " + movie.getAka());
				}
				// System.out.println(movie.toString());
				if (movieMap.containsKey(movie.getId())) {
					System.out.println("hasId: " + movie.getId() + " " + movie.getTitle());
				}
				if (movie.getMonth() < 0)
					System.out.println("month error: " + movie.getId() + " " + movie.getTitle());

				movieMap.put(movie.getId(), movie);
				for (String s : movie.getStudio().split("/"))
					studios.add(s.trim());
				//writer.write(movie.toString() + "\n");
			}
		}
		
		for (String s : studios) {
			System.out.println(s);
		}
		//writer.flush();
		writer.close();
	}

	public static void main(String[] args) throws Exception {
		List<Movie> movieList = BoxOffice.readMovies();
		new Predictor(movieList).addOmdbInfo();
	}
}
